package cn.zyjblogs.config.security;

import cn.zyjblogs.server.user.po.OauthUserDetails;
import cn.zyjblogs.starter.common.entity.constant.ContextKeyConstant;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author zhuyijun
 */
@Component
public class OauthUserAuthenticationConverter extends DefaultUserAuthenticationConverter {
    public OauthUserAuthenticationConverter(UserDetailsService userDetailsService) {
        setUserDetailsService(userDetailsService);
    }

    @Override
    public Authentication extractAuthentication(Map<String, ?> map) {
        OauthUserDetails oauthUserDetails = new OauthUserDetails();
        Object userName = map.get(ContextKeyConstant.USERNAME_KEY);
        if (userName != null) {
            oauthUserDetails.setUsername(userName.toString());
            if (map.containsKey(ContextKeyConstant.USER_ID_KEY)) {
                oauthUserDetails.setId((String) map.get(ContextKeyConstant.USER_ID_KEY));
            }
            if (map.containsKey(ContextKeyConstant.NAME_KEY)) {
                oauthUserDetails.setName((String) map.get(ContextKeyConstant.NAME_KEY));
            }
            if (map.containsKey(ContextKeyConstant.TENANT_ID_KEY)) {
                oauthUserDetails.setTenantId((String) map.get(ContextKeyConstant.TENANT_ID_KEY));
            }
            return new UsernamePasswordAuthenticationToken(oauthUserDetails, "N/A", getAuthorities(map));
        } else {
            return null;
        }
    }


    @Override
    public Map<String, ?> convertUserAuthentication(Authentication authentication) {
        Map<String, Object> response = new LinkedHashMap();
        response.put("user_name", authentication.getName());
        if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
            response.put("authorities", AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
        }
        return response;
    }

    private Collection<? extends GrantedAuthority> getAuthorities(Map<String, ?> map) {
        if (!map.containsKey("authorities")) {
            return Collections.emptyList();
        } else {
            Object authorities = map.get("authorities");
            if (authorities instanceof String) {
                return AuthorityUtils.commaSeparatedStringToAuthorityList((String) authorities);
            } else if (authorities instanceof Collection) {
                return AuthorityUtils.commaSeparatedStringToAuthorityList(StringUtils.collectionToCommaDelimitedString((Collection) authorities));
            } else {
                throw new IllegalArgumentException("Authorities must be either a String or a Collection");
            }
        }
    }
}
